#include "StdAfx.h"
#include "Segment.h"


namespace dhis
{
	//------------------------------------------------------------------------------
	void _getScales(CParameter* para,REALVec& vecScale)
	{
		if (para->m_customScale)
		{
			for (std::set<REAL>::iterator itr = para->m_scales.begin(); itr != para->m_scales.end(); ++itr) {
				vecScale.push_back(*itr);
			}
		} else {
			vecScale.push_back(para->m_startScale);
			while(1)
			{
				REAL dPrevScale = *vecScale.rbegin();
				if (dPrevScale >= para->m_stopScale) { break; }
				REAL dNxtScale = para->m_scaleFactor*dPrevScale;
				if (dNxtScale > para->m_stopScale) { dNxtScale = para->m_stopScale; }
				vecScale.push_back(dNxtScale);
			}
		}
	}

	//------------------------------------------------------------------------------
	void _parallelMergeScale(CBlockChessboard& chessboard,BlockMap& blocks,const CImageInfo* pImg,const CParameter* pPara,const REAL& scale,std::ofstream& strm)
	{
		while (1)
		{
			int nObjCount = 0;
			REAL dAvgDissim = 0.0;
			REAL dMinDissim = std::numeric_limits<REAL>::max();
			
			_computeStatistics(chessboard,blocks,dAvgDissim,dMinDissim,nObjCount);

			REAL dCurScale = sqrt(dAvgDissim);

			//strm << nObjCount <<"," << dMinDissim<<"," << dAvgDissim <<"," << dCurScale <<"," << dMaxDissim << std::endl;

			if (dCurScale > scale || nObjCount <= 2) { break; }

// 			if (nObjCount == 770)
// 			{
// 				_exportStatisticsShapeFile(chessboard,blocks,pImg,std::string("F:\\temp\\test_770\\"));
// 			}
			
			int i;
#pragma omp parallel for// private(i)
			for (i = 0; i < chessboard.GetBlockCount(); ++i) {
				int key = chessboard.GetBlockKey(i);
				CMacroBlock* block = blocks[key];

				_mergeBlockInner(block,pImg,pPara,dMinDissim);
			}
			_mergeBlockFrontier(chessboard,blocks,pImg,pPara,dMinDissim);
		}
	}

	//------------------------------------------------------------------------------
	void _mergeBlockInner(CMacroBlock* block,const CImageInfo* pImg,const CParameter* pPara,const REAL& scale)
	{
		if (block->m_objects.empty()) { return; }
		if (block->m_minDissim > scale) {
			block->m_mergedObjs.clear();
			return;
		}
		CNeighbor nbr;
		std::vector<int> vecTmp = block->m_mergedObjs;
		block->m_mergedObjs.clear();
		for (int i = 0; i < vecTmp.size(); ++i)
		{
			int objId = vecTmp[i];
			ObjectMap::iterator obj = block->m_objects.find(objId);
			if (obj == block->m_objects.end()) { continue; }
			if (obj->second->GetNeighbors().begin()->m_dissimCrit > scale) { continue; }
			if (_hasOutNeighborObject(block,obj->second))
			{
				block->m_mergedObjs.push_back(obj->first);
				continue;
			}

			ObjectMap::iterator nbobj = block->m_objects.find(obj->second->GetNeighbors().begin()->m_id);
			assert(nbobj != block->m_objects.end());

			if (_hasOutNeighborObject(block,nbobj->second))
			{
				block->m_mergedObjs.push_back(obj->first);
				continue;
			}

			REAL mergedPerim = obj->second->GetNeighbors().begin()->m_mergedPerim;
			_mergeObject(obj->second,nbobj->second);
			obj->second->Perimeter() = mergedPerim;
			
			NeighborList& nbrs = obj->second->GetNeighbors();
			for (NeighborList::iterator pos = nbrs.begin(); pos != nbrs.end(); ++pos)
			{
				ObjectMap::iterator nbnbobj = block->m_objects.find(pos->m_id);
				assert(nbnbobj != block->m_objects.end());
				nbnbobj->second->DeleteNeighbor(obj->first);
				nbnbobj->second->DeleteNeighbor(nbobj->first);
				pos->m_dissimCrit = calcRegionObjectDissimilarityCriterion(obj->second,nbnbobj->second,pImg,pPara,mergedPerim);
				nbr.Init(obj->first,obj->second->NumPixel(),pos->m_dissimCrit,mergedPerim);
				nbnbobj->second->AddNeighbor(nbr);
				nbnbobj->second->SortNeighbor();
				nbnbobj->second->CalculateAvgDissim();
			}

			obj->second->SortNeighbor();
			obj->second->CalculateAvgDissim();
			delete nbobj->second;
			block->m_objects.erase(nbobj->first);
		}
	}

	//------------------------------------------------------------------------------
	void _mergeBlockFrontier(CBlockChessboard& chessboard,BlockMap& blocks,const CImageInfo* pImg,const CParameter* pPara,const REAL& scale)
	{
		for (int k = 0; k < chessboard.GetBlockCount(); ++k)
		{
			int key = chessboard.GetBlockKey(k);
			CMacroBlock* block = blocks[key];
			if (block->m_mergedObjs.empty()) { continue; }
			CNeighbor nbr;
			for (int i = 0; i < block->m_mergedObjs.size(); ++i)
			{
				ObjectMap::iterator obj = block->m_objects.find(block->m_mergedObjs[i]);
				if (obj == block->m_objects.end()) { continue; }
				if (obj->second->GetNeighbors().begin()->m_dissimCrit > scale) { continue; }

				int nbrkey = chessboard.AtBlock(obj->second->GetNeighbors().begin()->m_id);
				assert(chessboard.IsBlockKey(nbrkey));
				ObjectMap::iterator nbobj = blocks[nbrkey]->m_objects.find(obj->second->GetNeighbors().begin()->m_id);
				assert(nbobj != blocks[nbrkey]->m_objects.end());

				REAL mergedPerim = obj->second->GetNeighbors().begin()->m_mergedPerim;
				_mergeObject(obj->second,nbobj->second);
				obj->second->Perimeter() = mergedPerim;

				NeighborList& nbrs = obj->second->GetNeighbors();
				for (NeighborList::iterator pos = nbrs.begin(); pos != nbrs.end(); ++pos)
				{
					int nbrnbrkey = chessboard.AtBlock(pos->m_id);
					assert(chessboard.IsBlockKey(nbrnbrkey));
					ObjectMap::iterator nbnbobj = blocks[nbrnbrkey]->m_objects.find(pos->m_id);
					assert(nbnbobj != blocks[nbrnbrkey]->m_objects.end());
					nbnbobj->second->DeleteNeighbor(obj->first);
					nbnbobj->second->DeleteNeighbor(nbobj->first);
					pos->m_dissimCrit = calcRegionObjectDissimilarityCriterion(obj->second,nbnbobj->second,pImg,pPara,mergedPerim);
					nbr.Init(obj->first,obj->second->NumPixel(),pos->m_dissimCrit,mergedPerim);
					nbnbobj->second->AddNeighbor(nbr);
					nbnbobj->second->SortNeighbor();
					nbnbobj->second->CalculateAvgDissim();
				}

				obj->second->SortNeighbor();
				obj->second->CalculateAvgDissim();
				delete nbobj->second;
				blocks[nbrkey]->m_objects.erase(nbobj->first);
			}
			blocks[k]->m_mergedObjs.clear();
		}
	}
}
